Repository navigation
Fix character-range highlights and retain debugLineFragments - #26
Conversation
…level highlight bounds
…BoxesForCharRange
…getBoxesForCharRange
vietnguyentuan2019
left a comment
There was a problem hiding this comment.
Thanks for the follow-up! 🙏 This is in good shape. Every point from the #19 review is addressed. I also checked that both strengthened tests actually catch regressions: with mergeGroup++ removed, the image test fails (one 0→208 rect), and with the isPreformatted guard removed, the pre test fails (80 vs 80). I merged this locally with current main (1.12.0). There are no conflicts, the full root+core suite passes (2526), and analyze is clean.
One thing before merge, in the ellipsis part of debugLineFragments():
ellipsisVisibleLength is always null on the fragment that's actually on the line. When layout truncates, it adds a new truncFrag ("visi…") to the line. But it sets ellipsisVisibleLength on the original fragment, which never reaches _lines (render_hyper_box_layout.dart ~L1322–1335). I reproduced it with:
<p>x</p><div style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap">visible head SECRET TAIL</div>at width 80. The line fragment reports text: "visi…", charStart: 1, charEnd: 6, ellipsisVisibleLength: null. The expected result is 4 visible chars, so charEnd: 5. The … glyph gets counted as source char 5. That causes two problems:
- The doc comment says consumers "can tell how much of a truncated fragment reached the screen", but they can't.
getBoxesForCharRange(5, 6)returns a rect over the…for the hidden charb.
The current test only checks containsKey('ellipsisVisibleLength'), so it can't catch this.
Suggested fix:
- In layout, set
ellipsisVisibleLength = clippedText.lengthontruncFrag. Do the same for the ellipsis-only fragment, with0. - In
debugLineFragments()andgetBoxesForCharRange(), usefragment.ellipsisVisibleLength ?? text.lengthas the fragment's char length.getSelectedTextalready does this. - Add a test with the HTML above that asserts
ellipsisVisibleLength == 4,charEnd == 5, andgetBoxesForCharRange(5, 6)is empty. The same harness exists intest/review_fixes_v1_3_2_test.dart.
Small stuff (non-blocking):
- The image test comment mentions commit
f5a313b, which no longer exists after the rebase. Could you drop the hash? - Could you add a line to the
getBoxesForCharRangedoc saying offsets are local to thisRenderHyperBox? In virtualized/auto mode (>10k chars), each chunk has its own box, and offsets restart at 0. - Optional: most of the per-fragment logic is duplicated from
getSelectionRects. A shared helper would be nice, but it's fine to leave as a follow-up.
Thanks again, nearly there!
- Set ellipsisVisibleLength on truncFrag and ellipsisFrag during layout - Use ellipsisVisibleLength in debugLineFragments to exclude ellipsis glyph - Unify getSelectionRects and getBoxesForCharRange via shared helper - Document RenderHyperBox coordinate locality in getBoxesForCharRange - Drop stale commit hash in boxes_for_char_range_test - Add regression test for truncated text bounds at narrow width Refs brewkits#19
|
Thanks so much for the thorough review and for catching this! 🙏 All of your points have been addressed in
Really appreciate your patience and guidance! Thanks again 🙏 |
|
Hello @vietnguyentuan2019 , While testing CJK EPUB documents containing large unspaced paragraphs (such as Project Gutenberg's Dream of the Red Chamber / 紅樓夢), I noticed a significant line-breaking performance issue in I investigated the problem and have prepared a potential fix with passing tests on branch Please let me know if you would prefer that I open a separate issue or pull request to discuss this, or if it is convenient to discuss it here. Thank you for your time and guidance. |
vietnguyentuan2019
left a comment
There was a problem hiding this comment.
Thanks for the quick turnaround! 🙏 Everything from the last review is addressed.
I checked 5a151ff locally merged with current main (1.12.0). There are no conflicts, analyze is clean, format is unchanged, and the full root+core suite passes (2527, which is the old count plus your new test). I also reverted just the truncFrag change, and the new test fails (Expected: <4>, Actual: <null>), so it really guards the fix. The shared _getFragmentBoxesForRange helper is a nice cleanup, and getSelectionRects keeps its old trimming behavior.
Two small behavior changes come with this. Both look right to me, I'm just noting them for the record:
else if→ifin the ellipsis path: whenfitWidth > 0but no characters fit on an empty line, we now show…instead of an empty line.- Selection highlights on a truncated fragment no longer cover the
…glyph, which matchesgetSelectedText.
Merging now. Thanks again for sticking with this through two rounds! 🙌
|
Thanks for digging into this, a 13s → ~250ms layout is a big win for CJK EPUBs! 🙏 Could you open it as a separate issue + PR? It's independent of #26 and touches the core line breaker, so I'd like to review it on its own. The issue can hold the repro and numbers, and the PR the fix. A few things that would help the review:
Looking forward to it! |
Character-range highlight geometry from brewkits#26 (by @DrkXo): RenderHyperBox.getBoxesForCharRange and debugLineFragments, plus the ellipsisVisibleLength fix on truncated line fragments. hyper_render requires hyper_render_core ^1.13.0. The other packages are unchanged and need no release. CHANGELOG headings, README, MIGRATION_GUIDE, CSS matrix and roadmaps updated.
Follow-up to #17 and replacement for closed PR #19. This updates character-range highlights for text scaling, whitespace, line geometry, and inline atoms, while retaining the requested line-fragment diagnostics with dedicated tests.
Changes
_getTextPainter()so highlights respect the active text scaler.debugLineFragments()to report positioned fragments, character ranges, line bounds, ruby text, and ellipsis visibility for laid-out content.Tests
boxes_for_char_range_test.dart: character-range geometry, preformatted whitespace, and an inline-image boundary that asserts two separate rectangles.debug_line_fragments_test.dart: wrapped fragment geometry, character ranges, line metadata, ruby text, ellipsis visibility, and the distinction fromdebugFragments().Validation